package mt.comm.implement;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.LinkedList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import mt.comm.implement.ClientSideMessage.Type;

public class ServerHandler {

	/** The messages from client to server. 
	 *This list and working with it how we did was not mandatory for the communication component to work
	 *however, it makes the user experience a lot better 
	 *since the GUI will not freeze each time orders are placed in a small interval between them */
	private BlockingQueue<ServerSideMessageImp> messagesFromClientToServer = new LinkedBlockingQueue<ServerSideMessageImp>(1);
	private BlockingQueue<ClientSideMessageImp> messagesFromServerToClient = new LinkedBlockingQueue<ClientSideMessageImp>(1);
	private LinkedList<Thread> activeThreads = new LinkedList<Thread>();
	private Socket socket;
	private ObjectInputStream in;
	private ObjectOutputStream out;
	private ClientCommImp clientComm;
	private ServerHandler handler = this;
	private String nickname;
	
	/**
	 * Constructs the ServerHandler and initiates the threads that will handle messages and the In and OutputStreams
	 * 
	 * @param clientComm
	 * @param socket
	 * @throws IOException
	 */
	public ServerHandler(ClientCommImp clientComm, Socket socket) throws IOException {
		this.socket = socket;
		this.clientComm = clientComm;
		this.nickname=clientComm.getNickname();
		in = new ObjectInputStream(socket.getInputStream());
		out = new ObjectOutputStream(socket.getOutputStream());
		activeThreads.add(new ThreadIncomingFromServer());
		activeThreads.add(new ThreadOutGoingFromClientTpServer());
		startThreads();
		
	}
	
	/**
	 * Starts the threads
	 */
	private void startThreads() {
		for (Thread iterable_element : getActiveThreads()) {
			iterable_element.start();
		}
		
	}

	/**
	 * This thread will listen for messages coming from the server 
	 * and add them to the queue to be processed by the client
	 * 
	 * @author Vlad
	 *
	 */
	private class ThreadIncomingFromServer extends Thread {
		@Override
		public void run() {
			try {
				while (!isInterrupted()) {
					ClientSideMessageImp messageIn = (ClientSideMessageImp) in
							.readObject();
					if (messageIn.getType().equals(Type.ERROR)) {
						clientComm.disconnect();
					} 
					BlockingQueue<ClientSideMessageImp> queue = getMessagesFromServerToClient();
					
					System.out.println(getNickname()+" recebi uma mensagem do tipo" + messageIn.getType().toString());
						System.out.println("Queue in serverhandler" + queue.hashCode());
						System.out.println("Mensagem: " + messageIn);
						queue.put(new ClientSideMessageImp(null, null, null));
						queue.put(new ClientSideMessageImp(null, null, null));
						queue.put(new ClientSideMessageImp(null, null, null));
						queue.put(new ClientSideMessageImp(null, null, null));
						queue.put(messageIn);
						
						System.out.println("Queue in serverhandler after add " + queue.toString());

						System.out.println(queue.size());
				}
			} catch (Exception e) {
			e.printStackTrace();
			} 
			//System.out.println("Morri thread in client");
		}
	}
	
	
	/**
	 * This thread will sends the messages from the client to the server
	 *
	 */
	private class ThreadOutGoingFromClientTpServer extends Thread{
		@Override
		public void run() {
				try {
					while(!isInterrupted()){
				
					ServerSideMessageImp messageOut = getMessagesFromClientToServer().take();
					out.writeObject(messageOut);
					}
					} catch (InterruptedException e) {
					//e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
					}
				
			}

		
		}


	/**
	 * Gets the messages form client to server 
	 * @return messagesFromClientToServer
	 */
	public BlockingQueue<ServerSideMessageImp> getMessagesFromClientToServer() {
		return messagesFromClientToServer;
	}


	/**
	 * Gets the Active threads
	 * @return activeThreads
	 */
	public LinkedList<Thread> getActiveThreads() {
		return activeThreads;
	}


	/**
	 * Gets the socket
	 * @return socket
	 */
	public Socket getSocket() {
		return socket;
	}


//	/**
//	 * Gets the  client comm
//	 * @return
//	 */
//	public ClientCommImp getClientComm() {
//		return clientComm;
//	}


	/**
	 * Gets the messages that are received from the Server.
	 *
	 * @return a BlockingQueue that contains ClientSideMessageImp.
	 */

//	/**
//	 * Gets the server handler
//	 * @return serverHandler
//	 */
//	public ServerHandler getHandler() {
//		return handler;
//	}


	/**
	 * Gets the nickname
	 * @return nickname
	 */
	public String getNickname() {
		return nickname;
	}


	/**
	 * Gets the messages form server to client queue
	 * @return messagesFromServerToClient
	 */
	public BlockingQueue<ClientSideMessageImp> getMessagesFromServerToClient() {
		return messagesFromServerToClient;
	}

	/**
	 * @param messagesFromServerToClient
	 */
//	public void setMessagesFromServerToClient(
//			BlockingQueue<ClientSideMessageImp> messagesFromServerToClient) {
//		this.messagesFromServerToClient = messagesFromServerToClient;
//	}

//	public void setMessagesFromClientToServer(
//			BlockingQueue<ServerSideMessageImp> messagesFromClientToServer) {
//		this.messagesFromClientToServer = messagesFromClientToServer;
//	}
//	
	
	
}
